{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 颜色直方图\n",
    "\n",
    "让我们回到我们的分类任务：将图像分类为白天图像或夜晚图像。 通过之前的学习，你已经知道如何使用原始像素值构造亮度特征，现在我们将尝试把像素强度直方图（颜色直方图）作为 **特征向量**。\n",
    "\n",
    "特征可以是有用值的数组。 即使你创建的过滤图像也被视为特征提取图像。特征向量是值的一维数组（或列表），当单个值不足以对图像进行分类时可以使用它们。\n",
    "\n",
    "在这个 notebook 中，你将看到如何创建一种常见类型的特征向量：**直方图**。 直方图是显示不同高度条的数据的一种图形显示方式。 每个柱会将数据（在这个案例中为像素值）分组为不同的范围，每个柱的高度表示数据落入该范围的次数。 所以，如果一个柱的高度更高，则表示有更多的数据落在了该特定范围内。\n",
    "\n",
    "让我们来看看HSV颜色直方图的样子。\n",
    "\n",
    "### 导入资源"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import cv2 # computer vision library\n",
    "\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import matplotlib.image as mpimg\n",
    "\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 读入日/夜图像并将其标准化\n",
    "\n",
    "我们将要分析两种图像：训练数据集中的一天一夜图像；同一场景的图像。 但是这些图像还没有被标准化，所以它们需要被调整为相同的。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Read in a day and a night image\n",
    "# These are directly extracted by name -- do not change\n",
    "day_image = mpimg.imread(\"day_night_images/training/day/20151102_074952.jpg\")\n",
    "night_image = mpimg.imread(\"day_night_images/training/night/20151102_175445.jpg\")\n",
    "\n",
    "\n",
    "# Make these images the same size\n",
    "width = 1100\n",
    "height = 600\n",
    "night_image = cv2.resize(night_image, (width, height))\n",
    "day_image = cv2.resize(day_image, (width, height))\n",
    "\n",
    "# Visualize both images\n",
    "f, (ax1, ax2) = plt.subplots(1, 2, figsize=(20,10))\n",
    "ax1.set_title('night')\n",
    "ax1.imshow(night_image)\n",
    "ax2.set_title('day')\n",
    "ax2.imshow(day_image)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 创建HSV直方图\n",
    "\n",
    "首先，将这些图像转换为HSV颜色空间。 然后使用numpy的 [直方图函数](https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.histogram.html) 将颜色值组合到范围中。 其中，Bin指的是数值范围，如暗度值为0-15，亮度值为200-255。\n",
    "\n",
    "使用np.histogram（），你不必指定bin数量或范围，但在这里我已任意选择了个bin并指定其范围=（0,256），这样便于获得有序的bin尺寸。np.histogram（）返回两个数组的元组。例如，在这种情况下，h_hist [0]包含每个bin的计数，而h_hist [1]包含bin边（因此它比h_hist [0]长一个元素）。\n",
    "\n",
    "为了将这些结果绘制成图，我们可以从bin边缘计算bin中心。 在这个示例例中，每个直方图都有相同的bin，所以我只使用rhist bin边缘就可以了：你可以定义bin的数量。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def hsv_histograms(rgb_image):\n",
    "    # Convert to HSV\n",
    "    hsv = cv2.cvtColor(rgb_image, cv2.COLOR_RGB2HSV)\n",
    "\n",
    "    # Create color channel histograms\n",
    "    h_hist = np.histogram(hsv[:,:,0], bins=32, range=(0, 180))\n",
    "    s_hist = np.histogram(hsv[:,:,1], bins=32, range=(0, 256))\n",
    "    v_hist = np.histogram(hsv[:,:,2], bins=32, range=(0, 256))\n",
    "    \n",
    "    # Generating bin centers\n",
    "    bin_edges = h_hist[1]\n",
    "    bin_centers = (bin_edges[1:]  + bin_edges[0:len(bin_edges)-1])/2\n",
    "\n",
    "    # Plot a figure with all three histograms\n",
    "    fig = plt.figure(figsize=(12,3))\n",
    "    plt.subplot(131)\n",
    "    plt.bar(bin_centers, h_hist[0])\n",
    "    plt.xlim(0, 180)\n",
    "    plt.title('H Histogram')\n",
    "    plt.subplot(132)\n",
    "    plt.bar(bin_centers, s_hist[0])\n",
    "    plt.xlim(0, 256)\n",
    "    plt.title('S Histogram')\n",
    "    plt.subplot(133)\n",
    "    plt.bar(bin_centers, v_hist[0])\n",
    "    plt.xlim(0, 256)\n",
    "    plt.title('V Histogram')\n",
    "    \n",
    "    return h_hist, s_hist, v_hist\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Call the function for \"night\"\n",
    "night_h_hist, night_s_hist, night_v_hist = hsv_histograms(night_image)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Call the function for \"day\"\n",
    "day_h_hist, day_s_hist, day_v_hist = hsv_histograms(day_image)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 观察差异"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Which bin do most V values fall in?\n",
    "# Does the Hue channel look helpful?\n",
    "# What patterns can you see that might distinguish these two images?\n",
    "\n",
    "# Out of 32 bins, if the most common bin is in the middle or high up, then it's likely day\n",
    "fullest_vbin_day = np.argmax(day_v_hist[0])\n",
    "fullest_vbin_night = np.argmax(night_v_hist[0])\n",
    "\n",
    "\n",
    "print('Fullest Value bin for day: ', fullest_vbin_day)\n",
    "print('Fullest Value bin for night: ', fullest_vbin_night)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "## TODO: Create and look at RGB histograms\n",
    "# Practice what you've learned and look at RGB color histograms of these same images"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 求和并创建特征向量\n",
    "\n",
    "为了保持空间信息，对沿图像的列或行的像素值进行求和也是一种有用的方法，这样可以让你在空间中看到各种颜色值的尖峰。\n",
    "\n",
    "我们以夜间图像为例， 这些图像大多是黑暗的，但有很多来自人造灯光的小亮点。 我将查看图像中的Value组件，使用np.sum（）将各列中的像素值相加，然后将该总和绘制成图。\n",
    "\n",
    "### TODO：将白天图像的V分量进行求和，并与夜晚图像进行对比"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Convert the night image to HSV colorspace\n",
    "hsv_night = cv2.cvtColor(night_image, cv2.COLOR_RGB2HSV)\n",
    "\n",
    "# Isolate the V component\n",
    "v = hsv_night[:,:,2]\n",
    "\n",
    "# Sum the V component over all columns (axis = 0)\n",
    "v_sum = np.sum(v[:,:], axis=0)\n",
    "\n",
    "\n",
    "f, (ax1, ax2) = plt.subplots(1, 2, figsize=(20,10))\n",
    "\n",
    "ax2.set_title('Value sum over columns')\n",
    "ax1.plot(v_sum)\n",
    "\n",
    "ax2.set_title('Original image')\n",
    "ax2.imshow(night_image, cmap='gray')"
   ]
  }
 ],
 "metadata": {},
 "nbformat": 4,
 "nbformat_minor": 2
}
